<?php
namespace Main;

include 'commands.php';

class Commandee
{
    const NO_ID = '0000';
    
    public function __construct()
    {
    }
    
    public function getCommand($msg)
    {
        return $msg[0].$msg[1];
    }
    
    public function setPlayer($id)
    {
        return str_pad((string)$id, 4, '0', STR_PAD_LEFT);
    }
    
    public function getPlayer($msg)
    {
        return (int)($msg[2].$msg[3].$msg[4].$msg[5]);
    }
    
    public function getMessage($msg)
    {
        return strip_tags(substr($msg, 6));
    }
    
    public function getAllPlayers(array $players)
    {
        // later compress it (result)?

        $result = Commands::SET_ALL_PLAYERS.self::NO_ID;
        foreach ($players as $player_id => $player)
        {
            $result .= $this->setPlayer($player_id) . $player->getName() . ',';
        }
        if (isset($result[7])) $result = substr($result, 0, -1);
        return $result;
    }
    
    public function process($user, $msg, \Main\WsServer $server)
    {
        // the msg sent by user

        $user_id = $server->getPlayers()->getIdBySocket($user->socket);
        
        switch ($this->getCommand($msg))
        {
            case Commands::LOGIN:
            {
                if ($this->getMessage($msg) === '' &&
                    ! strpos($this->getMessage($msg), ',') &&
                    strlen($this->getMessage($msg)) < 10)
                        break;
                
                $server->getPlayer($user_id)->
                    setName($this->getMessage($msg));
                
                // set player id
                $server->sendToOne($user->socket, Commands::SET_ID.$this->setPlayer($user_id));
                // send all users but this to new user
                $server->sendToOne($user->socket, $this->getAllPlayers($server->getPlayers()->getPlayers()));
                // send the new user to all but this
                $server->sendToAll($user->socket, Commands::SET_NEW_PLAYER.$this->setPlayer($user_id).$this->getMessage($msg));
            } break;

            case Commands::GAME_REQUEST:
            {
                if ( ! $server->getPlayers()->getPlayer((int)$this->getMessage($msg))->stFree() ||
                     ! $server->getPlayers()->getPlayer($user_id)->stFree())
                    break;

                // first asks the second for a game
                $aim_socket = $server->getPlayers()->getSocketById((int)$this->getMessage($msg));
                $server->sendToOne($aim_socket, Commands::GAME_REQUEST.
                                                $this->setPlayer($this->getPlayer($msg)).
                                                $server->getPlayers()->getPlayer($this->getPlayer($msg))->getName());
                $server->getPlayers()->getPlayer((int)$this->getMessage($msg))->setState(\Entity\States::GAME_DECISION);
            }
            break;
            
            case Commands::GAME_REQUEST_DECLINE:
            {
                $server->getPlayers()->getPlayer($this->getPlayer($msg))->setState(\Entity\States::FREE);
            }
            break;
        
            case Commands::GAME_REQUEST_ACCEPT:
            {
                if ( ! $server->getPlayers()->issetPlayer($this->getPlayer($msg)) ||
                     ! $server->getPlayers()->getPlayer($this->getPlayer($msg))->stFree())
                {
                    $server->getPlayers()->getPlayer($user_id)->setState(\Entity\States::FREE);
                    break;
                }
                
                // states change
                $server->getPlayers()->getPlayer($user_id)->setState(\Entity\States::INGAME);
                $server->getPlayers()->getPlayer($this->getPlayer($msg))->setState(\Entity\States::INGAME);
                
                // add map
                $server->getMaps()->addMap($user_id, $this->getPlayer($msg));
                
                // send the game started message to the players
                // here '0' / '1' -> my_step (who whos, eg. x/o), '0' starts the game
                $server->sendToOne( $server->getPlayers()->getSocketById($user_id),
                                    Commands::GAME_START . self::NO_ID . '0' . $this->setPlayer($this->getPlayer($msg)) . $server->getPlayers()->getPlayer($this->getPlayer($msg))->getName());
                $server->sendToOne( $server->getPlayers()->getSocketById((int)$this->getPlayer($msg)),
                                    Commands::GAME_START . self::NO_ID . '1' . $this->setPlayer($user_id) . $server->getPlayers()->getPlayer($user_id)->getName());
                
                // players next step? 0 - his turn, 1 - oppenent's turn
                $server->getPlayers()->getPlayer($user_id)->setNextStep(TRUE);
                $server->getPlayers()->getPlayer($this->getPlayer($msg))->setNextStep(FALSE);
            }
            break;
            
            case Commands::GAME_STEP:
            {
                $pos_x = (int)substr($this->getMessage($msg), 0, 2);
                $pos_y = (int)substr($this->getMessage($msg), 2, 2);
                
                // outOfBounds?
                if ($pos_x < 0 || $pos_x > \Entity\Map::ROWNUM - 1 ||
                    $pos_y < 0 || $pos_y > \Entity\Map::COLNUM - 1) break;
                
                // is his turn?
                if ( ! $server->getPlayers()->getPlayer($user_id)->isHisTurn()) break;
                
                // is there a map and not isset the field
                $map = $server->getMaps()->getMapByPlayerId($user_id);
                if ($map === NULL || $map->issetField($pos_x, $pos_y)) break;
                
                // p1 -> 1, p2 -> 2, whos step?
                $map->setField($pos_x, $pos_y, $map->isPlayer1($user_id) ? 1 : 2);
                
                // next step to false
                $server->getPlayers()->getPlayer($user_id)->setNextStep(FALSE);
                $server->getPlayer($map->getOtherPlayer($user_id))->setNextStep(TRUE);
                
                // send step
                $server->sendToOne($server->getPlayers()->getSocketById($map->getOtherPlayer($user_id)),
                                    Commands::GAME_STEP . $this->setPlayer($user_id) .
                                    substr($this->getMessage($msg), 0, 2) .
                                    substr($this->getMessage($msg), 2, 2));
                
                // Is there five in a row? WON / LOST (if not exactly five, so more)
                // 
                // player1
                $won_spots      = array();
                $calcFive       = $map->calcFive($map->getP1Fields(), 1, $won_spots);
                $match_result   = 0;
                if ($calcFive === \Entity\Map::WON)
                    $match_result = 1;
                else if ($calcFive === \Entity\Map::LOST)
                    $match_result = 2;
                // player2
                else
                {
                    $calcFive = $map->calcFive($map->getP2Fields(), 2, $won_spots);
                    if ($calcFive === \Entity\Map::WON)
                        $match_result = 2;
                    else if ($calcFive === \Entity\Map::LOST)
                        $match_result = 1;
                }
                
                // p1 won
                if ($match_result === 1)
                {
                    $server->sendToOne($server->getPlayers()->getSocketById($map->getP1()),
                                        Commands::GAME_WON_SPOTS . self::NO_ID .
                                        $won_spots[0] .
                                        str_pad($won_spots[1][0], 2, '0', STR_PAD_LEFT) .
                                        str_pad($won_spots[1][1], 2, '0', STR_PAD_LEFT) .
                                        str_pad($won_spots[2][0], 2, '0', STR_PAD_LEFT) .
                                        str_pad($won_spots[2][1], 2, '0', STR_PAD_LEFT));
                    $server->sendToOne($server->getPlayers()->getSocketById($map->getP2()),
                                        Commands::GAME_LOST_SPOTS . self::NO_ID .
                                        $won_spots[0] .
                                        str_pad($won_spots[1][0], 2, '0', STR_PAD_LEFT) .
                                        str_pad($won_spots[1][1], 2, '0', STR_PAD_LEFT) .
                                        str_pad($won_spots[2][0], 2, '0', STR_PAD_LEFT) .
                                        str_pad($won_spots[2][1], 2, '0', STR_PAD_LEFT));
                    $server->sendToOne($server->getPlayers()->getSocketById($map->getP1()),
                                        Commands::GAME_WON . self::NO_ID);
                    $server->sendToOne($server->getPlayers()->getSocketById($map->getP2()),
                                        Commands::GAME_LOST . self::NO_ID);
                    
                    $server->getMaps()->delMap($map->getId());
                    $server->getPlayers()->getPlayer($map->getP1())->setState(\Entity\States::FREE);
                    $server->getPlayers()->getPlayer($map->getP2())->setState(\Entity\States::FREE);
                }
                // p2 won
                else if ($match_result === 2)
                {
                    $server->sendToOne($server->getPlayers()->getSocketById($map->getP1()),
                                        Commands::GAME_LOST_SPOTS . self::NO_ID .
                                        $won_spots[0] .
                                        str_pad($won_spots[1][0], 2, '0', STR_PAD_LEFT) .
                                        str_pad($won_spots[1][1], 2, '0', STR_PAD_LEFT) .
                                        str_pad($won_spots[2][0], 2, '0', STR_PAD_LEFT) .
                                        str_pad($won_spots[2][1], 2, '0', STR_PAD_LEFT));
                    $server->sendToOne($server->getPlayers()->getSocketById($map->getP2()),
                                        Commands::GAME_WON_SPOTS . self::NO_ID .
                                        $won_spots[0] .
                                        str_pad($won_spots[1][0], 2, '0', STR_PAD_LEFT) .
                                        str_pad($won_spots[1][1], 2, '0', STR_PAD_LEFT) .
                                        str_pad($won_spots[2][0], 2, '0', STR_PAD_LEFT) .
                                        str_pad($won_spots[2][1], 2, '0', STR_PAD_LEFT));
                    $server->sendToOne($server->getPlayers()->getSocketById($map->getP1()),
                                        Commands::GAME_LOST . self::NO_ID);
                    $server->sendToOne($server->getPlayers()->getSocketById($map->getP2()),
                                        Commands::GAME_WON . self::NO_ID);
                    
                    $server->getMaps()->delMap($map->getId());
                    $server->getPlayers()->getPlayer($map->getP1())->setState(\Entity\States::FREE);
                    $server->getPlayers()->getPlayer($map->getP2())->setState(\Entity\States::FREE);
                }
            }
            break;

            case Commands::CHAT_MSG:
            {
                if (strlen($this->getMessage($msg)) > 64) break;
                
                $act_msg = strip_tags($this->getMessage($msg));
                if ($act_msg === "") break;

                $chat_msg = $server->getPlayers()->getPlayer($user_id)->getName() .
                            ':' .
                            $act_msg;

                $server->sendToAll( NULL,
                                    Commands::CHAT_MSG . $this->setPlayer($user_id) . $chat_msg);
            }
            break;

            default:
            {
            } break;
        }
    }
}

#eof
